/*
 * util.cpp
 *
 *  Created on: Jun 24, 2012
 *      Author: burek
 */

#include "util.h"
#include <cmath>

#define RSEEDS (256)
#define RRAND_MAX (32767)

#ifndef M_PI
#define M_PI (3.14159265359f)
#endif

#define TWO_PI (6.2831853071f)

int rnums[RSEEDS] =
{7755,22514,9910,24474,3072,12157,21533,8522,32236,18756,18420,6831,31455,
 24842,32614,1979,4243,6781,10748,4612,13595,1120,23695,9089,32580,12882,22813,
 26086,20372,13895,18184,15289,7162,12315,11141,6746,14569,14853,21190,31784,
 16430,4732,5538,8107,156,27323,25233,22391,2969,28205,29613,18972,9380,29167,
 7228,22352,8230,7722,22869,12416,48,7468,11874,11579,24744,27273,5412,9286,
 31963,29820,23949,20166,7361,21730,22776,12692,2060,23895,858,14065,13124,15107,
 11075,28269,32389,11583,29445,29960,8455,18105,16629,20880,31042,4669,14927,9410,
 24359,22011,9511,16781,32455,6741,20243,10796,3643,31107,32582,8108,27574,25481,
 6867,15495,5721,18225,19515,30781,13651,24466,27637,15418,4124,12623,4887,24700,
 1935,19646,23571,24570,9597,1482,7251,17247,13985,27558,6600,28510,8492,23147,
 7286,16618,27710,19512,23288,1858,24156,11753,3867,11711,6135,4033,30124,14131,
 24540,11724,19777,240,12936,7486,19268,28968,13393,281,10315,3818,19861,20142,
 3505,7151,30163,20475,10161,8354,3860,57,28143,1136,4459,10570,18702,8356,19196,
 7454,14677,13862,32026,18239,28124,23223,26744,5985,9213,6089,16336,29148,
 18766,13748,17937,26852,10456,28766,1010,8032,27683,26645,14590,10894,10210,
 19875,28219,31830,15855,20455,30282,25665,24920,20656,14637,14604,26123,10772,
 6079,23683,19439,21249,2794,26041,13732,21379,2279,27667,29619,20813,13916,
 22918,27616,3918,20422,16092,1897,14842,728,3555,9091,4451,30095,23868,23181,
 12958,30036,23832,10093,2432,1224,29102,13618,10097};

int __rpos = 0;

inline int rrand()
{
	__rpos = __rpos % RSEEDS;
	//rnums[(__rpos + RSEEDS - 1) % RSEEDS] ^= rnums[__rpos];
	return rnums[__rpos++];
}

int rPow(int base, int exp)
{
	int result = 1;
	while (exp)
	{
		if (exp & 1)
			result *= base;
		exp >>= 1;
		base *= base;
	}

	return result;
}

float getAngleRad(float x1, float y1, float x2, float y2)
{
	return atan2(y1 - y2, x1 - x2);
}

float getAngleDeg(float x1, float y1, float x2, float y2)
{
	return atan2(y1 - y2, x1 - x2) * RAD_TO_DEG;
}

void angClampRad(float & angle)
{
	while(angle < 0.0f) angle += M_PI * 2.0f;
	while(angle > M_PI * 2.0f) angle -= M_PI * 2.0f;
}

float angDiffRad(float a1, float a2)
{
	float diff = std::abs(a1 - a2);
	while(diff >= TWO_PI) diff -= TWO_PI;
	return (diff >= M_PI) ? TWO_PI - diff : diff;
}

float angDiffDeg(float a1, float a2)
{
	float diff = std::abs(a1 - a2);
	while(diff >= 360.0f) diff -= 360.0f;
	return (diff >= 180.0f) ? 360.0f - diff : diff;
}

float angDiffSgnRad(float a1, float a2)
{
	while(a1 < 0.0f) a1 += TWO_PI;
	while(a2 < 0.0f) a2 += TWO_PI;
	while(a1 >= TWO_PI) a1 -= TWO_PI;
	while(a2 >= TWO_PI) a2 -= TWO_PI;
	float diff = a2 - a1;
	if(diff < M_PI && diff > -M_PI)
		return diff;
	else if(diff > M_PI)
		return -(TWO_PI - diff);
	else
		return  TWO_PI + diff;
}

float lerp(float a, float b, float x)
{
	return x * (b - a) + a;
}

float lerpC(float a, float b, float x)
{
	if(x < 0.0f) x = 0.0f;
	if(x > 1.0f) x = 1.0f;
	return x * (b - a) + a;
}

bool chance(int percent)
{
	return (rrand() % 10000 < percent * 100);
}

int randRangeI(int min, int max)
{
	return rrand() % (max - min + 1) + min;
}

float randRangeF(float min, float max)
{
	return ((float)rrand() / (float)RRAND_MAX) * (max - min) + min;
}

float randRangeFS(float min, float max)
{
	return (((float)rrand() / (float)RRAND_MAX) * (max - min) + min);
}

int getDistI(int x1, int y1, int x2, int y2)
{
	int dx = x2 - x1, dy = y2 - y1;
	return (int)sqrt((float)(dx * dx + dy * dy));
}

float getDistF(float x1, float y1, float x2, float y2)
{
	float dx = x2 - x1, dy = y2 - y1;
	return sqrt(dx * dx + dy * dy);
}

bool rayPlaneIntersect(Vec3D point, Vec3D vector, Vec3D surfPoint, Vec3D surfNormal, Vec3D & result)
{
	if(surfNormal.dot(vector) > 0.0f) return false;
	return false;
}

bool projectRayToZ(Vec3D point, Vec3D vector, float Z, Vec3D & result)
{
	if(point.Z < Z)
		return false;
	if(vector.Z >= 0.0f)
		return false;
	float dist = (point.Z - Z) / -vector.Z;
	result = point + vector * dist;
	return true;
}
